-
Notifications
You must be signed in to change notification settings - Fork 121
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(partition): monotonic font size scaling #681
feat(partition): monotonic font size scaling #681
Conversation
Codecov Report
@@ Coverage Diff @@
## master #681 +/- ##
==========================================
+ Coverage 72.63% 72.94% +0.30%
==========================================
Files 266 266
Lines 8686 8711 +25
Branches 1696 1696
==========================================
+ Hits 6309 6354 +45
+ Misses 2338 2318 -20
Partials 39 39
Continue to review full report at Codecov.
|
@@ -151,6 +151,10 @@ export const configMetadata = { | |||
type: 'number', | |||
reconfigurable: false, // there's no real reason to reconfigure it; finding the largest possible font is good for readability | |||
}, | |||
monotonic: { | |||
dflt: false, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have a strong opinion, but to me seems that a monotonic
font scale avoids misunderstanding when reading the chart. I prefer having it on
by default. The consumer then can opt to turn it off to maximize the font size depending on space. As you already highlighted in the PR description it's a tradeoff between readability and understandability.
@rshen91 @nickofthyme what do you think?
We should not be afraid of turning it on and mark the PR as breaking change, but we should prefer giving the user a good default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Glad to switch, I was on the fence about it and the config is there either way. A single long word or narrow box can turn subsequent boxes less legible, if at all (see PR desc.) ie. assumes more about the data, iow more vulnerable input-wise. But, monotonically shrinking text is preattentively preferable 😄 The breaking change tipped the balance for me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
...maybe it's not even a breaking change? We don't have an API contract that specifies text maximization. We should retain freedom for changing data and text ink that honors API contracts. Worth a discussion, a strict interpretation would require a breaking change for any pixel level visual change, while a too loose interpretation would throw curveballs to dependency maintainers
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I agree, should default to true
. I don't know if making it a breaking change is necessary though, It's not that noticeable of a change in most cases and it always looks better, IMHO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have strong feelings, but I think it's great we're making this available. I'm leaning towards the stance stated above, it's probably best to set it on by default and just have the option for consumers to set it off if readability suffers. I don't think it's a breaking change and it's nice that the consumer can always set it to false if they liked the font sizing beforehand.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the common thinking, done in e166746
@@ -62,6 +62,7 @@ export interface FillFontSizeRange { | |||
minFontSize: Pixels; | |||
maxFontSize: Pixels; | |||
idealFontSizeJump: Ratio; | |||
monotonic: boolean; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a tsdoc to describe the effect of this property monotonic
monotonic: boolean; | |
/** the fonts are scaled in.... **/ | |
monotonic: boolean; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
note: it got renamed in a subsequent commit e166746
type NumberMap = (n: number) => number; | ||
|
||
/** @internal */ | ||
export function monotonicHillClimb( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
even if this method is internal, a quick description of this method in a tsdoc is useful
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -182,7 +182,7 @@ function rectangleConstruction(treeHeight: number, topGroove: number) { | |||
} | |||
|
|||
/** @internal */ | |||
export function shapeViewModel( | |||
export function shapeViewModel<C>( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see where we are using this generic, do we really need it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, good catch, it was used at some point but no more, will remove
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fontWeight, | ||
valueFormatter, | ||
padding, | ||
} = Object.assign( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you add a type here that this merge is going to resolve to?
} = Object.assign( | |
}: MyType = Object.assign( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's currently no specific type for this, and making one up for this wouldn't be terribly informative as it's just the reiteration of what's in the const
bracket. I'm planning further extraction from this function (not in this PR though) as it's still too large, in which case a proper boundary, carrying these resolved/cascaded values, needs to arise. But it needs a bit of design work, glad to chat about it on a call separately or on the team sync, the upshot is that I feel uncomfortable typing this transitional thing without that design. Still open to being convinced if I can learn about the reasons 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure that's fine, this merging of several values is just hard to decipher. Even if the types were defined inline that would be better, something like...
} = Object.assign( | |
}: { | |
fontWeight: number, | |
valueFormatter: () => string, | |
padding: number, | |
} = Object.assign( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or even a combination of types that satisfy the resolved values, surely you have all the types to combine into the correct values.
} = Object.assign( | |
}: MyFontType & Pick<MyStyleType, 'style'> = Object.assign( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Anyway, this in fine for now just wanted to start the discussion. 👍
…-squashed # Conflicts: # integration/tests/__image_snapshots__/all-test-ts-baseline-visual-tests-for-all-stories-sunburst-sunburst-with-two-layers-visually-looks-correct-1-snap.png
# [19.4.0](v19.3.0...v19.4.0) (2020-05-28) ### Bug Fixes * **partition:** consider legendMaxDepth on legend size ([#654](#654)) ([9429dcf](9429dcf)), closes [#639](#639) ### Features * **partition:** enable grooves in all group layers ([#666](#666)) ([f5b4767](f5b4767)) * **partition:** linked text overflow avoidance ([#670](#670)) ([b6e5911](b6e5911)), closes [#633](#633) * **partition:** monotonic font size scaling ([#681](#681)) ([ea2489b](ea2489b)), closes [#661](#661) * **tooltip:** improve positioning with popperjs ([#651](#651)) ([6512950](6512950)), closes [#596](#596)
🎉 This PR is included in version 19.4.0 🎉 The release is available on: Your semantic-release bot 📦🚀 |
# [19.4.0](elastic/elastic-charts@v19.3.0...v19.4.0) (2020-05-28) ### Bug Fixes * **partition:** consider legendMaxDepth on legend size ([opensearch-project#654](elastic/elastic-charts#654)) ([20cc6ec](elastic/elastic-charts@20cc6ec)), closes [opensearch-project#639](elastic/elastic-charts#639) ### Features * **partition:** enable grooves in all group layers ([opensearch-project#666](elastic/elastic-charts#666)) ([b1bdfb3](elastic/elastic-charts@b1bdfb3)) * **partition:** linked text overflow avoidance ([opensearch-project#670](elastic/elastic-charts#670)) ([59617db](elastic/elastic-charts@59617db)), closes [opensearch-project#633](elastic/elastic-charts#633) * **partition:** monotonic font size scaling ([opensearch-project#681](elastic/elastic-charts#681)) ([d46767c](elastic/elastic-charts@d46767c)), closes [opensearch-project#661](elastic/elastic-charts#661) * **tooltip:** improve positioning with popperjs ([opensearch-project#651](elastic/elastic-charts#651)) ([61d1d9a](elastic/elastic-charts@61d1d9a)), closes [opensearch-project#596](elastic/elastic-charts#596)
Summary
fill_text_layout.ts
got broken up, and some changes were needed by this (typed arg lists) as well as by switching to the hill climber, but otherwise its logic remained unchanged (fill part of mocks didn't change except the two changed 3-layer ones)any
sDetails
The feature implements per-layer monotonic font scaling.
The 3-layer sunburst and treemap have per layer knobs to see the effect.
The tradeoff is reduced scaling in legibility: a single bad case (eg. narrow box, long word) can yield a small, maybe unrenderably small text for all the subsequent boxes too, even if those could otherwise be rendered. For this reason, and also, not to cause a breaking change, the current PR has
layers: [ { fillLabel: { monotonic: false } } ]
as a default; can be changed if it's important enough to cause a breaking change. Also, maybe the current logic could be augmented by still allowing the use of the smallest font size even if there was a larger value with text that didn't fit even with the smallest font size.The logic currently achieves monotonicity per layer. This is uncontroversial with the treemap as groove texts are bound to be small. For sunburst, it looks preferable too, because otherwise a single, small inner slice can lead to small fonts in all the outer rings. However it can still lead to cases where an outer sector has a larger font than an inner sector of lower value, eg.
Mineral fuels
vsMachinery / North America
(can be the other way around too). Once we introduce global monotonicity, new tradeoffs of diminishing returns arise 😸The per layer monotonicity also means that font size constraints do not get reset for groups. In other words, if there are two top level groups A and B in a two-layer chart, then the font size of a node in Group A can't be larger than any of the font sizes of nodes in Group B that have higher values.
There's no constraint for linearity or other proportionality. So it's still possible to have unbalanced texts, eg. if the biggest box is
"China"
and a very close runner-up is"United States"
then the font size for the latter will be unproportionately small, also depending on box aspect ratios.The current issue and PR response leaves other aspects of "text ink weight perception" unaddressed: text lengths and even the character shapes in the texts impact visual weight. Further, possible improvements might help, but again, there are diminishing returns, so prioritization would be needed:
...
"UK"
(or ISO"GB"
/"GBR"
)"United Kingdom"
"United Kingdom of Great Britain and Northern Ireland"
These would bring improvements in addition to helping with text ink proportionality
Checklist
Delete any items that are not applicable to this PR.
src/index.ts
(and stories only import from../src
except for test data & storybook)